package com.zkh.myframe.core;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zkh.myframe.annotation.Aspect;
import com.zkh.myframe.annotation.Configuration;
import com.zkh.myframe.annotation.Mapper;
import com.zkh.myframe.aspect.AspectProxy;
import com.zkh.myframe.aspect.AspectSuper;
import com.zkh.myframe.database.mapper.proxy.MapperProxy;
import com.zkh.myframe.exception.FrameException;
import com.zkh.myutils.bean.BeanUtils;
import com.zkh.myutils.proxy.Proxy;
import com.zkh.myutils.system.ConfigLoader;
import com.zkh.myutils.utils.Regexp;
import com.zkh.myutils.utils.StringUtils;

/**
 * 框架全局工具类，备用
 * @author zkh
 */
public class FrameUtils {
	
	//存储Resource资源，如果使用单例模式，则从此Map中获取
	private static Map<Class<?>, Object> resourceMap = new HashMap<Class<?>, Object>();
	
	//HttpServletRequest和HttpServletResponse对象容器
	private static ThreadLocal<HttpServletRequest> servletRequests = new ThreadLocal<>();
	private static ThreadLocal<HttpServletResponse> servletResponses = new ThreadLocal<>();
	
	/**
	 * 获取HttpServletRequest对象
	 * @return
	 */
	public static HttpServletRequest getHttpServletRequest() {
		return servletRequests.get();
	}
	
	/**
	 * 获取HttpServletResponse对象
	 * @return
	 */
	public static HttpServletResponse getHttpServletResponse() {
		return servletResponses.get();
	}
	
	/**
	 * 获取链接后缀
	 * @param uri
	 * @return
	 */
	public static String getUrlSuffix(String uri) {
		//空或/结尾
		if(StringUtils.isEmpty(uri) || Regexp.isEndWith("/+", uri)) {
			return "";
		}
		//临时索引变量
		int i = uri.lastIndexOf("/");
		//存在
		if(i>-1) {
			uri = uri.substring(i+1);i=-1;
		}
		//检测后缀
		i = uri.lastIndexOf(".");
		//检测是否有后缀名
		if(i>-1 && !uri.endsWith(".")) {
			return uri.substring(i+1);
		}
		return "";
	}
	
	/**
	 * 创建一个Resource资源类（非单例）
	 * @param cls 类Class
	 * @return
	 */
	public static <T> T getResourceClass(Class<T> cls) {
		return getResourceClass(cls, false);
	}
	
	/**
	 * 获取一个Resource资源类
	 * @param cls 类Class
	 * @param isSingleton 是否使用单例获取资源类
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getResourceClass(Class<T> cls, boolean isSingleton) {
		try {
			//资源类
			Object instance = null;
			//是否已存在实例
			boolean exist = false;
			//配置bean
			boolean config = cls.isAnnotationPresent(Configuration.class);
			//如果是单例或配置Bean，且已创建过，则直接返回
			if((isSingleton || config) && (exist=resourceMap.containsKey(cls))) {
				instance = resourceMap.get(cls);
			}else {
				//实例不存在或不是单例模式，则创建新的资源类
				instance = getInstanceFromClass(cls, config);
				//加载资源
				loadResource(cls, instance, isSingleton);
				//缓存一份，供单例使用
				if((isSingleton || config) && !exist) {
					resourceMap.put(cls, instance);
				}
			}
			//返回实例
			return (T) instance;
		}catch(Exception e) {
			throw new FrameException("资源类创建失败", e);
		}
	}

	/**
	 * 创建实例
	 * @param clazz 待创建实例的类Class
	 * @return
	 */
	private static Object getInstanceFromClass(Class<?> clazz, boolean config) throws Exception {
		//配置类
		if(config) {
			return getInstanceFromConfigClass(clazz);
		}
		//切面注解
		Aspect aspectTemp = null;Aspect.List aspectListTemp = null;
		//如果是Mapper，则使用代理MapperProxy来处理
		if(clazz.isAnnotationPresent(Mapper.class)) {
			return Proxy.newProxyInstance(FrameUtils.class.getClassLoader(), clazz, new MapperProxy());
		}
		//检查是否有切面注解
		else if((aspectTemp = clazz.getAnnotation(Aspect.class))!=null || 
				(aspectListTemp = clazz.getAnnotation(Aspect.List.class))!=null){
			//获取定义的切面
			Aspect[] aspectList = aspectTemp!=null ? new Aspect[] {aspectTemp} : aspectListTemp.value();
			//接收方法和处理器的容器
			List<String> methodPatternList = new ArrayList<String>();
			List<AspectSuper> handlerList = new ArrayList<AspectSuper>();
			//代理方法pattern取并集
			StringBuffer sb = new StringBuffer();
			//遍历处理
			for(Aspect aspect: aspectList) {
				//代理方法正则
				if(!methodPatternList.contains(aspect.pattern())) {
					sb.append('(').append(aspect.pattern()).append(")|");
				}
				//保存代理正则和代理处理对象
				methodPatternList.add(aspect.pattern());
				handlerList.add(aspect.aspect().newInstance());
			}
			//创建切面代理
			AspectProxy aspectProxy = new AspectProxy(methodPatternList, handlerList);
			//生成代理
			return Proxy.newProxyInstance(FrameUtils.class.getClassLoader(), clazz, sb.substring(0, sb.length()-1), aspectProxy);
		}else{
			return clazz.newInstance();
		}
	}
	
	/**
	 * 创建一个配置类
	 * @param cls
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException 
	 */
	@SuppressWarnings("unchecked")
	private static Object getInstanceFromConfigClass(Class<?> cls) throws InstantiationException, IllegalAccessException {
		//获取key值
		String[] keys = cls.getAnnotation(Configuration.class).key().split("\\.");
		//配置值
		Map<String, Object> map = ConfigLoader.getAll();
		//获取配置
		for(String key: keys) {
			//获取值
			Object v = map.get(key);
			//值为空
			if(v==null) {
				return cls.newInstance();
			}else if(v instanceof Map) {
				map = (Map<String, Object>) v;
			}else {
				throw new InstantiationException("无法将" + v.getClass().getName() + "类型转换为" + cls.getName() + "类型");
			}
		}
		//返回对象
		return BeanUtils.mapToBean(map, cls);
	}

	/**
	 * 加载类所包含的资源
	 * @param clazz 实例类的class
	 * @param instance 实例
	 */
	private static void loadResource(Class<?> clazz, Object instance, boolean isSingleton) throws Exception {
		//是否是代理类，代理类包含_proxyHandler字段
		boolean isProxy = readerMethod(clazz.getDeclaredFields(), instance, isSingleton);
		//如果是代理类，还要处理父类方法
		if(isProxy) {
			readerMethod(clazz.getSuperclass().getDeclaredFields(), instance, isSingleton);
		}
	}
	
	/**
	 * 遍历方法
	 * @param fields
	 * @param instance
	 * @return
	 * @throws Exception
	 */
	private static boolean readerMethod(Field[] fields, Object instance, boolean isSingleton) throws Exception {
		//是否是代理类，代理类包含_proxyHandler字段
		boolean isProxy = false;
		//检查方法上是否有Resource注解
		for(Field field: fields){
			//判断是否是代理类
			isProxy = isProxy || "_proxyHandler".equals(field.getName());
			//如果存在Resource注解
			if(field.isAnnotationPresent(Resource.class)){
				//获取资源名称
				String resource = field.getType().getName();
				//设置可访问
				field.setAccessible(true);
				//注入的类的class
				Class<?> resourceClass = Class.forName(resource);
				//注入的类的实例
				Object target = getResourceClass(resourceClass, isSingleton);
				//注入值
				field.set(instance, target);
				//调用自身给注入的类注入依赖的资源
				loadResource(resourceClass, target, isSingleton);
			}
		}
		return isProxy;
	}
 
	/**
	 * 获取HttpServletRequest对象容器
	 * @return
	 */
	static ThreadLocal<HttpServletRequest> getServletRequestContainer() {
		return servletRequests;
	}
	
	/**
	 * 获取HttpServletResponse对象容器
	 * @return
	 */
	static ThreadLocal<HttpServletResponse> getServletResponseContainer() {
		return servletResponses;
	}
}
